package cn.iocoder.yudao.module.product.service.spu;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.esim.api.esproduct.EsProductApi;
import cn.iocoder.yudao.module.esim.api.esproduct.dto.EsProductDTO;
import cn.iocoder.yudao.module.esim.enums.esproduct.EsProductTypeEnum;
import cn.iocoder.yudao.module.infra.util.CountryUtil;
import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueSaveReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.SearchESimSpuReqVO;
import cn.iocoder.yudao.module.product.dal.dataobject.property.ProductPropertyValueDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
import cn.iocoder.yudao.module.product.enums.property.PropertyValueTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.DeliveryTypeEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductSkuStatusEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import cn.iocoder.yudao.module.product.enums.spu.ProductTypeEnum;
import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
import cn.iocoder.yudao.module.product.service.sku.IESimSkuService;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Description:
 * Author: li
 * Date: 2024/3/14
 */
@Service
@Slf4j
public class ESimSpuServiceImpl implements IESimSpuService {
    @Resource
    private ProductPropertyValueService propertyValueService;
    @Lazy
    @Resource
    private IESimSkuService simSkuService;
    @Resource
    private ProductSkuService productSkuService;
    @Resource
    private ProductSpuService productSpuService;
    @Lazy
    @Resource
    private EsProductApi esProductApi;
    @Resource
    private ProductSpuMapper productSpuMapper;

    @Override
    public List<AppProductSpuRespVO> searchESimSpu(SearchESimSpuReqVO reqVO) {
        final Long coveragePropertyId = reqVO.getCoveragePropertyId();
        final List<String> coveragePropertyValueList = reqVO.getCoveragePropertyValueList();
        final Integer esDataAllowanceMb = reqVO.getEsDataAllowanceMb();
        final Integer esValidityPeriodDaysMin = reqVO.getEsValidityPeriodDaysMin();
        final Integer esValidityPeriodDaysMax = reqVO.getEsValidityPeriodDaysMax();

        // 查询覆盖范围的spuId
        final List<ProductPropertyValueDO> propertyValueList = propertyValueService.selectGroupBySpuId(
                PropertyValueTypeEnum.SPU, coveragePropertyId, coveragePropertyValueList
        );
        final Set<Long> propertySpuIdSet = propertyValueList.stream().map(v -> v.getSpuId()).collect(Collectors.toSet());
        log.info("查询覆盖范围的spuId, coveragePropertyId = {}, coveragePropertyValueList = {}, propertySpuIdSet = {}",
                coveragePropertyId, coveragePropertyValueList, propertySpuIdSet);
        if (CollUtil.isEmpty(propertyValueList)) {
            return null;
        }

        // 查询SKU
        final List<ProductSkuDO> productSkuList = simSkuService.searchSpuByDataAllowanceAndValidityPeriodDays(
                propertySpuIdSet, esDataAllowanceMb, esValidityPeriodDaysMin, esValidityPeriodDaysMax
        );
        final List<Long> spuIdSet = productSkuList.stream().map(v -> v.getSpuId()).collect(Collectors.toList());
        log.info("查询符合sku条件的spuId, esDataAllowanceMb = {}, esValidityPeriodDaysMin = {}, esValidityPeriodDaysMax = {}, spuIdSet = {}",
                esDataAllowanceMb, esValidityPeriodDaysMin, esValidityPeriodDaysMax, spuIdSet);
        if (CollUtil.isEmpty(productSkuList)) {
            return null;
        }

        // 查询SPU
        final List<ProductSpuDO> spuList = productSpuService.getSpuList(spuIdSet);

        // 转换为VO
        final List<AppProductSpuRespVO> voList = BeanUtils.toBean(spuList, AppProductSpuRespVO.class);

        // 设置搜索出来的skuIds
        final Map<Long, List<ProductSkuDO>> spuId2Skus = CollectionUtils.convertMultiMap(productSkuList, ProductSkuDO::getSpuId);
        if (CollUtil.isNotEmpty(voList)) {
            for (AppProductSpuRespVO vo : voList) {
                final List<ProductSkuDO> productSkuDOS = spuId2Skus.get(vo.getId());
                final List<Long> skuIds = productSkuDOS.stream().map(v -> v.getId()).collect(Collectors.toList());
                vo.setSkuIds(skuIds);
            }
        }

        return voList;
    }

    @Override
    public void createSpuFromEsProduct() {
        final List<EsProductDTO> allEsProducts = esProductApi.getAllEsProducts();
        // 按照country分组
        final Map<String, List<EsProductDTO>> spuMap = CollectionUtils.convertMultiMap(allEsProducts, EsProductDTO::getCountry);

        for (Map.Entry<String, List<EsProductDTO>> entry : spuMap.entrySet()) {
            final String country = entry.getKey();
            final List<EsProductDTO> esProductDTOS = entry.getValue();
            log.info("按照country分组, country = {}, esProductDTOS.size = {}", country, esProductDTOS.size());

            // 拆分
            final List<String> countryList = new ArrayList<>(Arrays.asList(country.split(";")));
            Collections.sort(countryList);
            final String esCountryHash = new Digester(DigestAlgorithm.MD5).digestHex(String.join(",", countryList));

            // 查询spu
            final ProductSpuDO spuDO = productSpuMapper.getSpuByEsCountryHash(esCountryHash);
            log.info("查询spu, esCountryHash = {}, spuDO = {}", esCountryHash, spuDO != null);

            final Long spuId;
            if (spuDO == null) {
                // 创建spu
                final EsProductTypeEnum type = EsProductTypeEnum.fromValue(esProductDTOS.get(0).getType());
                final String name = esProductDTOS.get(0).getName();
                spuId = createSpu(name, esCountryHash, type);

                // 给spu设置属性值
                createPropertyValue(spuId, countryList);
            } else {
                spuId = spuDO.getId();
            }

            // 创建或更新sku
            final List<ProductSkuDO> skuDOList = createOrUpdateSkus(spuId, esProductDTOS);

            // 设置spu价格
            productSpuService.initSpuFromSkus(spuId, spuDO, skuDOList);
        }
    }

    // 创建或更新sku
    private List<ProductSkuDO> createOrUpdateSkus(Long spuId, List<EsProductDTO> esProductDTOS) {
        final List<ProductSkuDO> skuDOList = new ArrayList<>();
        for (EsProductDTO esProduct : esProductDTOS) {
            final String esProductId = esProduct.getId();
            ProductSkuDO sku = simSkuService.getSkuByEsProductId(esProductId);
            if (sku == null) {
                sku = createSku(spuId, esProduct);
            } else {
                updateSku(esProduct, sku);
            }
            skuDOList.add(sku);
        }
        return skuDOList;
    }

    private void updateSku(EsProductDTO esProduct, ProductSkuDO sku) {
        sku.setName(esProduct.getName());
        sku.setIntroduction(esProduct.getDescription());
        sku.setEsDataAllowanceMb(esProduct.getDataAllowanceMb());
        sku.setEsValidityPeriodDays(esProduct.getValidityPeriodDays());
        productSkuService.updateSku(sku);
        log.info("更新sku, spuId = {}, skuId = {}", sku.getSpuId(), sku.getId());
    }

    private ProductSkuDO createSku(Long spuId, EsProductDTO esProduct) {
        final ProductSkuDO sku = new ProductSkuDO();
        sku.setSpuId(spuId);
        sku.setStatus(ProductSkuStatusEnum.ENABLE.getStatus());
        sku.setStock(Integer.MAX_VALUE);
        sku.setPrice(RandomUtil.randomInt(1, 100 * 10));
        sku.setCostPrice(sku.getPrice());
        sku.setMinPurchaseQuantity(1);
        sku.setMaxPurchaseQuantity(1);
        sku.setEsProductId(esProduct.getId());

        sku.setName(esProduct.getName());
        sku.setIntroduction(esProduct.getDescription());
        sku.setEsDataAllowanceMb(esProduct.getDataAllowanceMb());
        sku.setEsValidityPeriodDays(esProduct.getValidityPeriodDays());

        final Long skuId = productSkuService.createSku(sku);
        log.info("创建sku, spuId = {}, skuId = {}", spuId, skuId);
        return sku;
    }

    // 给spu设置属性值
    private void createPropertyValue(Long spuId, List<String> countryList) {
        for (String country : countryList) {
            final ProductPropertyValueSaveReqVO vo = new ProductPropertyValueSaveReqVO();
            vo.setPropertyId(0L);
            vo.setName(country);
            vo.setSpuId(spuId);
            final String countryCode = CountryUtil.getCountryCode(country);
            vo.setStructuredValue(countryCode);
            propertyValueService.createPropertyValue(PropertyValueTypeEnum.SPU, vo);
        }
        log.info("给spu设置属性值, spuId = {}, countryList = {}", spuId, countryList);
    }

    // 创建spu
    private Long createSpu(String name, String esCountryHash, EsProductTypeEnum type) {
        ProductSpuDO spuDO;
        spuDO = new ProductSpuDO();
        spuDO.setName(name);
        switch (type) {
            case COUNTRY:
                spuDO.setCategoryId(3L);
                break;
            case AREA:
                spuDO.setCategoryId(4L);
                break;
            case GLOBAL:
                spuDO.setCategoryId(5L);
                break;
        }
        spuDO.setSort(0);
        spuDO.setSubCommissionType(false);
        spuDO.setProductType(ProductTypeEnum.ESIM_CARD.getValue());
        spuDO.setVirtualProduct(true);
        spuDO.setStatus(ProductSpuStatusEnum.ENABLE.getStatus());
        spuDO.setDeliveryTypes(Arrays.asList(DeliveryTypeEnum.NO_DELIVERY_NEEDED.getValue()));
        spuDO.setEsCountryHash(esCountryHash);
        spuDO.setCurrencyCode("CNY");
        productSpuMapper.insert(spuDO);
        final Long spuId = spuDO.getId();
        log.info("创建spu, esCountryHash = {}, name = {}, spuId = {}", esCountryHash, name, spuId);
        return new Long(spuId);
    }

    public static void main(String[] args) {

    }
}
